// 注意:
// 不要传入空的数组到此接口中
// 不使用 min/max() 这个名称，会和其他平台宏函数重名
#ifndef xpack_math_maximum
#define xpack_math_maximum
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::math_maximum::inc
#include"define/base_type.hpp"
#include"interface/can_compare.hpp"
#include"interface/initializer_list.hpp"
#include"interface/unified_seq.hpp"
#include"macro/xexport.hpp"
#include"macro/xunlikely.hpp"
#include"utils/get_prop_value.hpp"
#include"utils/value_holder.hpp"
#pragma pop_macro("xuser")

namespace mixc::math_maximum::origin{
    template<class type_t>
    // 不使用 type_t const &，因为如果参数是右值，
    // 那么生命周期达不到返回后的位置，这个在编译器开优化模式才能看到，调试模式会隐匿这个问题
    inline type_t maximum(type_t left, type_t right){
        return left > right ? left : right;
    }

    template<class item_t, class list_t = inc::initializer_list<item_t>, class cmp_t = decltype(inc::default_compare<item_t>)>
    requires(inc::can_unified_seqlizex<list_t, item_t> and inc::can_compare<cmp_t, item_t>)
    inline inc::value_holder<item_t> maximumx(list_t && list, cmp_t const & compare = inc::default_compare<item_t>){
        auto ary        = inc::unified_seq<list_t>(list);
        auto len        = ary->length();
        auto i_max      = uxx{};
        xunlikely(len == 0){
            return {};
        }

        for(uxx i = 1; i < len; i++){
            if (compare(ary[i_max], ary[i]) < 0){
                i_max   = i;
            }
        }
        return { ary[i_max], i_max };
    }

    template<class item_t, class list_t = inc::initializer_list<item_t>, class cmp_t = decltype(inc::default_compare<item_t>)>
    requires(inc::can_unified_seqlizex<list_t, item_t> and inc::can_compare<cmp_t, item_t>)
    inline item_t maximum(list_t && list, cmp_t const & compare = inc::default_compare<item_t>){
        return maximumx<item_t, list_t, cmp_t>((list_t &&)list, compare)->value; // 如果数组为空会出现段错误
    }

    // 这是个 dummy 接口，
    // 要求外部使用 inc::xmaximum_field(type, field, list); 这种方式调用
    // 不要直接使用 xmaximum_field() 宏
    template<class value_t>
    inline decltype(auto) xmaximum_field(value_t && value){
        return (value_t &&)value;
    }

    // 同上
    template<class value_t>
    inline decltype(auto) xmaximum_fieldx(value_t && value){
        return (value_t &&)value;
    }

    /**
    xstruct 中将类型排到宏最后一个参数是因为没有选择，在定义时无法通过 typedef 或者 using 起个别名
    而函数就不一样，type 可以起别名然后再作为参数传入宏中，这样就不会出现模板类型中有逗号导致被当成多个参数分隔
    此外，让元素列表作为第三个参数，可能是 { xxx, xxx } 这种使用化括号包裹元素的列表，
    宏函数中只有小括号中的逗号不会作为宏参数分隔符，所以让元素列表作为可变参数部分可以避免这个问题

    struct ax{
        int foo;
        // ...
    };

    ax list[10];

    // do some init for list
    ...

    // get the max field of ax::foo
    int max_foo = xmaximum_field(ax, .foo, list);
    
    // if is ax pointer array
    ax * list[10];

    // ...

    // 不使用 ax::foo 这种宏参数，因为位域不支持这种操作
    int max_foo = xmaximum_field(ax, ->foo, list);
    //                               ~~ is pointer operation
     */
    #define xmaximum_field(TYPE,FIELD,...)                                                                      \
        xmaximum_field(                                                                                         \
            ::mixc::math_maximum::inc::get_prop_value(                                                          \
                ::mixc::math_maximum::origin::maximum<TYPE>(__VA_ARGS__, xcmp_field(FIELD, TYPE)) FIELD         \
            )                                                                                                   \
        )

    #define xmaximum_fieldx(TYPE,FIELD,...)                                                                     \
        xmaximum_fieldx(([&](){                                                                                 \
            auto result = ::mixc::math_maximum::origin::maximumx<TYPE>(__VA_ARGS__, xcmp_field(FIELD, TYPE));   \
            using value_t = decltype(::mixc::math_maximum::inc::get_prop_value(result->value() FIELD));         \
            if (result->is_hold_value){                                                                         \
                auto value = ::mixc::math_maximum::inc::get_prop_value(result->value() FIELD);                  \
                return ::mixc::math_maximum::inc::value_holder<value_t>(value, result->index);                  \
            }                                                                                                   \
            else{                                                                                               \
                return ::mixc::math_maximum::inc::value_holder<value_t>{};                                      \
            }                                                                                                   \
        })())
}

#endif

// 示意外部可以不用包含 xcmp.hpp，可以直接使用
#include"macro/xcmp.hpp"
xexport_space(mixc::math_maximum::origin)